Skip to content

[WC-3442] feat(datagrid-web): add onBeforeExport and onAfterExport event actions - #2392

Open
r0b1n wants to merge 4 commits into
mainfrom
feat/datagrid-export-events
Open

[WC-3442] feat(datagrid-web): add onBeforeExport and onAfterExport event actions#2392
r0b1n wants to merge 4 commits into
mainfrom
feat/datagrid-export-events

Conversation

@r0b1n

@r0b1n r0b1n commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Adds two optional action properties — On before export and On after export — to Data Grid 2, giving developers a logging/auditing hook into the export lifecycle
  • onBeforeExport fires fire-and-forget immediately before the first datasource page fetch; receives gridName, columnTitles, chunkSize, fileName, sheetName, and startTime
  • onAfterExport fires after the export resolves (success or abort); additionally receives exportedItemCount, status ("success" | "aborted"), and endTime
  • Both actions are optional and fully independent; the export flow is unchanged when neither is configured
  • fileName and sheetName are passed by the external export caller via exportData() options and default to empty strings when not provided

Changes

  • Datagrid.xml — two new <property type="action"> blocks with <actionVariables> in the Events group
  • DatagridProps.d.ts — updated manually to match XML (will be regenerated on build)
  • DSExportRequest.ts — exposed get loaded() and get limit() public getters (renamed private fields to _loaded / _limit)
  • ExportController.ts — added BeforeExportArgs / AfterExportArgs types; name constructor param; beforeexport / afterexport events in ControllerEvents; public on() method (returns Unsubscribe); emits both events in exportData()
  • useDataExport.ts — stores latest ActionValue props in refs; subscribes to beforeexport / afterexport once per controller lifetime via useEffect([entry]); effect cleanup unsubscribes automatically
  • ExportController.spec.ts — 5 new unit tests covering all event scenarios

Test plan

  • All existing unit tests pass (pnpm run test)
  • No lint errors
  • In Studio Pro: configure onBeforeExport and onAfterExport on a Data Grid 2, trigger an export, verify both microflows/nanoflows are called with correct variable values
  • Verify status is "aborted" when the user cancels mid-export
  • Verify export works normally when neither action is configured

@r0b1n
r0b1n requested a review from a team as a code owner August 19, 2026 07:35
@github-actions

This comment has been minimized.

@r0b1n
r0b1n force-pushed the feat/datagrid-export-events branch from e1fc392 to 5134ce1 Compare August 19, 2026 13:38
@github-actions

This comment has been minimized.

@r0b1n
r0b1n force-pushed the feat/datagrid-export-events branch from 5134ce1 to 5bace00 Compare August 20, 2026 13:49
@github-actions

This comment has been minimized.

r0b1n added 3 commits August 21, 2026 13:51
- Narrow AfterExportArgs.status to "success" | "aborted" union type
- Move onBeforeExport callback before handler(req) to match spec ordering
- Update openspec artifacts to replace filterCondition with fileName/sheetName
  and document the intentional removal of filterCondition
@r0b1n
r0b1n force-pushed the feat/datagrid-export-events branch from 5bace00 to 158efd6 Compare August 21, 2026 11:52
@github-actions

Copy link
Copy Markdown
Contributor

AI Code Review

⚠️ Approved with suggestions — low-severity items only, safe to merge


What was reviewed

File Change
src/Datagrid.xml Two new action properties with actionVariables in the Events group
typings/DatagridProps.d.ts Manually updated to add onBeforeExport/onAfterExport typed ActionValue props
src/features/data-export/DSExportRequest.ts Exposed get loaded() and get limit() public getters; renamed private fields
src/features/data-export/ExportController.ts Added name, BeforeExportArgs/AfterExportArgs types, on() method, event emissions
src/features/data-export/useDataExport.ts Stores action props in refs; subscribes to events once per controller lifetime
src/features/data-export/__tests__/ExportController.spec.ts 5 new unit tests for event scenarios
src/features/data-export/__tests__/useDataExport.spec.ts 6 new unit tests for hook wiring and ref pattern
CHANGELOG.md Unreleased entry added
openspec/changes/datagrid-export-events/** Design artifacts (out of scope for code review)

Skipped (out of scope): dist/, pnpm-lock.yaml

All CI checks could not be fetched (command requires approval in this environment).


Findings

⚠️ Low — afterexport fires while the export lock is still held

File: src/features/data-export/ExportController.ts line 138
Problem: afterexport is emitted immediately after req.send() resolves, but this.locked is not set to false until the datasource view-state has been restored — which is an async step that happens later (the sourcechange listener at line 158). If a developer's onAfterExport microflow/nanoflow completes quickly enough to trigger another export before that restoration completes, the second call to exportData() will return silently without error because this.locked is still true.

// ExportController.ts — current order
await req.send();
this.emitter.emit("afterexport", { ... });   // locked === true here

this.datasource.setLimit(snapshot.limit);
// ... async restoration ...
// locked === false only after sourcechange confirms restoration

This could be documented (e.g. "a new export triggered from onAfterExport will be deferred until the current export fully unwinds"), or the afterexport emission could be moved to after locked = false inside the sourcechange listener at line 162 — though that changes the semantics slightly.


⚠️ Low — columnTitles comma-joins column headers without escaping

File: src/features/data-export/ExportController.ts line 99
Problem: columnTitles is built by joining headers with ",". A column header that contains a comma (e.g. "Last Name, First Name") will produce an ambiguous string ("Last Name, First Name,City") that a Mendix developer parsing the variable cannot reliably split. The variable's <actionVariable> description in the XML is empty, so there is no hint about this format.

Fix (minimal): Add a description to the XML action variable so consumers know what to expect:

<actionVariable key="columnTitles" caption="Column Titles" type="String" />
<!-- add: <description>Comma-separated list of visible column header captions.</description> -->

Or, if reliable round-trip parsing matters, consider a different separator (e.g. |) or JSON-encode the array.


Positives

  • The ref pattern (onBeforeExportRef.current) is correctly applied so the subscription established on mount always reads the latest ActionValue without stale-closure risk, and the single useEffect([entry]) subscription avoids redundant re-subscriptions on each render.
  • canExecute is checked before every action.execute() call in useDataExport.ts, consistent with Mendix Pluggable Widgets API conventions.
  • The useDataExport.spec.ts test "reads the latest ActionValue from ref without resubscribing" directly validates the most subtle invariant introduced by this PR — good targeted coverage.
  • afterexport is emitted for both "success" and "aborted" paths (the abort is handled because req.abort() emits loadend, which resolves the send() promise), so the pairing with onBeforeExport is maintained in all exit paths.
  • CHANGELOG entry is present, user-facing, and describes the behavior without leaking implementation details.

@gjulivan gjulivan changed the title feat(datagrid-web): add onBeforeExport and onAfterExport event actions [WC-3442] feat(datagrid-web): add onBeforeExport and onAfterExport event actions Aug 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants